package cn.iotab.iotkit.transport.api.access.device;

import cn.iotab.iotkit.transport.api.access.handler.DeviceMessageSender;
import cn.iotab.iotkit.transport.api.access.handler.DeviceSessionOps;
import cn.iotab.iotkit.transport.api.access.handler.adaptor.DeviceMessageConverter;
import cn.iotab.iotkit.transport.api.access.model.message.DeviceMessageReply;
import cn.iotab.iotkit.transport.api.access.model.custom.firmware.PushUpgradeFirmwareMessage;
import cn.iotab.iotkit.transport.api.access.model.custom.firmware.PushUpgradeFirmwareMessageReply;
import cn.iotab.iotkit.transport.api.access.model.custom.function.FunctionInvokeMessage;
import cn.iotab.iotkit.transport.api.access.model.custom.function.FunctionInvokeMessageReply;
import cn.iotab.iotkit.transport.api.access.model.custom.property.PropertyReadMessage;
import cn.iotab.iotkit.transport.api.access.model.custom.property.PropertyReadMessageReply;
import cn.iotab.iotkit.transport.api.access.model.custom.property.PropertyPushMessage;
import cn.iotab.iotkit.transport.api.access.model.custom.property.PropertyPushMessageReply;
import cn.iotab.iotkit.transport.api.common.message.msg.down.CloseSessionCmd;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DeviceOperator {


    private final DeviceMessageSender deviceMessageSender;
    private final DeviceSessionOps deviceSessionOps;

    public DeviceOperator(DeviceMessageSender deviceMessageSender, DeviceSessionOps deviceSessionOps) {
        this.deviceMessageSender = deviceMessageSender;
        this.deviceSessionOps = deviceSessionOps;
    }

    /**
     * 转换response
     *
     * @param <T>
     * @return
     */
    @SuppressWarnings("all")
    private static <T extends DeviceMessageReply> ListenableFuture<T> convert(ListenableFuture<DeviceMessageReply> future, Class<T> tClass) {
        if (future == null){
            return null;
        }
        return Futures.transform(future, reply -> {
            return DeviceMessageConverter.convertMessageReply(reply, tClass);
        }, MoreExecutors.directExecutor());
    }


    /**
     * 读取设备属性
     *
     * @param message
     * @return
     */
    public ListenableFuture<PropertyReadMessageReply> getProperty(PropertyReadMessage message) {
        ListenableFuture<DeviceMessageReply> future = deviceMessageSender.sendMessage(message);
        return convert(future, PropertyReadMessageReply.class);
    }

    /**
     * 下发设备属性
     *
     * @param message
     * @return
     */
    public ListenableFuture<PropertyPushMessageReply> pushProperty(PropertyPushMessage message) {
        ListenableFuture<DeviceMessageReply> future = deviceMessageSender.sendMessage(message);
        return convert(future, PropertyPushMessageReply.class);
    }

    /**
     * 调用设备功能
     *
     * @param message
     * @return
     */
    public ListenableFuture<FunctionInvokeMessageReply> invokeFunction(FunctionInvokeMessage message) {
        ListenableFuture<DeviceMessageReply> future = deviceMessageSender.sendMessage(message);
        return convert(future, FunctionInvokeMessageReply.class);
    }

    /**
     * 推送升级消息
     *
     * @param message
     * @return
     */
    public ListenableFuture<PushUpgradeFirmwareMessageReply> pushUpgradeFirmware(PushUpgradeFirmwareMessage message) {
        ListenableFuture<DeviceMessageReply> future = deviceMessageSender.sendMessage(message);
        return convert(future, PushUpgradeFirmwareMessageReply.class);
    }

    /**
     * 断开设备
     * @param sessionId
     * @param message
     */
    public void disconnect(String sessionId, String message) {
        deviceSessionOps.disconnect(sessionId, new CloseSessionCmd(message));
    }

    /**
     * 断开设备
     * @param productKey
     * @param deviceId
     * @param message
     */
    public void disconnect(String productKey, String deviceId, String message) {
        deviceSessionOps.disconnect(productKey, deviceId, new CloseSessionCmd(message));
    }
}
